package cn.com.main;

import cn.com.bean.IdDto;
import cn.com.enums.HttpsMethod;
import cn.com.spring.annotation.Async;
import cn.com.utils.AopUtil;
import cn.com.utils.FileUtil;
import cn.com.utils.FunctionUtil;
import cn.com.utils.HttpClientUtil;
import cn.com.utils.ObjectMapperUtils;
import cn.com.utils.TimerCountUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 打tage
 *
 * @author LiuGuodong
 * @date 2024/01/17
 */
@Slf4j
public class CurlRequest {

    /**
     * 打tag的url
     */
    public static final String URL = "http://10.182.0.99:3000/tags";
    public static final String STR = "-";
    /**
     * 分支名称
     */
    public static String BRANCH_NAME = "help";

    /**
     * 延迟
     */
    public static final int DELAYED = 1000;

    /**
     * 异步代理
     */
    private static CurlRequest myProxy;

    static {
        try {
            myProxy = AopUtil.getAsyncProxy(CurlRequest.class);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    static ThreadPoolExecutor executor = new ThreadPoolExecutor(30, 50, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(DELAYED), new ThreadPoolExecutor.CallerRunsPolicy());

    static BufferedReader scanner = new BufferedReader(new InputStreamReader(System.in));

    //添加注释
    public static void main(String[] args) throws Exception {
        //查询需要打包的id
        FileUtil.createFileIfNotExists();
        List<IdDto> idList = new ArrayList<>(getIdList());
        Set<String> tagList = new TreeSet<>();
        FileUtil.inputTagName(tagList);
        BRANCH_NAME = FileUtil.getBranchName();

        FunctionUtil.clearConsole();
        while (true) {
            String branchName;
            long stop = TimerCountUtil.stop();

            System.out.print("\n请输入分支名称(或命令): ");
            branchName = scanner.readLine();
            System.out.println();
            if (branchName != null && branchName.trim().isEmpty()) {
                branchName = BRANCH_NAME;
            }
            if (FunctionUtil.functionalProcessing(branchName, tagList)) {
                continue;
            }
            if (!branchName.contains("-")) {
                System.out.println("请检查分支名是否正确!");
                continue;
            }
            String[] split = branchName.split(" ");
            String tagName = getTagName(split);
            if (tagList.contains(tagName)) {
                System.out.println("该tag已存在!");
                System.out.println(tagName);
                continue;
            }
            TimerCountUtil.start();

            String finalBranchName = split[0];
            idList.forEach(id -> {
                Map<String, String> parameters = new HashMap<>();
                parameters.put("value", String.valueOf(id.getId()));
                parameters.put("tag_name", tagName);
                parameters.put("release_description", tagName);
                parameters.put("ref", finalBranchName);

                String buildUrl = HttpClientUtil.buildUrl(URL, parameters);
                myProxy.execution(buildUrl, builder -> builder.post(RequestBody.create(new byte[0])));
            });
            tagList.add(tagName);
            System.out.println(tagName);
            FileUtil.outputTageName(tagName);

        }

    }


    /**
     * 生成标签名的工具方法。
     * 标签名由输入的字符串数组构建而成，包括第一个非空字符串和当前时间的部分。
     * 时间部分格式为yyyyMMddHHmm。
     * 如果输入的字符串数组为空，则返回空字符串。
     *
     * @param split 字符串数组，用于构建标签名
     * @return 生成的标签名字符串
     */
    private static String getTagName(String[] split) {
        // 获取当前时间并格式化为yyyyMMddHHmm
        String format = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

        // 如果输入的字符串数组为空，返回空字符串
        if (split.length == 0) {
            return "";
        }

        // 构建标签名的 StringBuilder
        StringBuilder builder = new StringBuilder();

        // 将第一个非空字符串和时间部分添加到标签名中
        builder.append(split[0])
                .append(STR)
                .append(format, 0, 8)
                .append(STR)
                .append(format, 8, 12)
                .append(STR)
                .append(format.substring(12));

        // 遍历剩余的字符串数组，将非空字符串添加到标签名中
        for (int i = 1; i < split.length; i++) {
            String str = split[i];
            if (str.trim().isEmpty()) {
                continue;
            }
            builder.append(STR).append(str);
        }

        // 返回生成的标签名字符串
        return builder.toString();
    }


    private static List<IdDto> getIdList() {
        // 从文件中读取 ID 列表
        List<IdDto> query = FileUtil.query();
        if (query.isEmpty()) {
            // 如果文件中没有 ID 列表，则输出正在初始化
            System.out.println("正在初始化...");
            // 更新 ID 列表
            myProxy.updateId();
            // 从文件中读取 ID 列表
            query = FileUtil.query();
        }
        // 提交一个线程来更新 ID 列表
        //ThreadPoolUtils.executeTask(CurlRequest::updateId);
        myProxy.updateId();

        // 返回 ID 列表
        return query;
    }

    /**
     * 更新id
     */
    @Async
    public void updateId() {
        List<IdDto> idList = new CopyOnWriteArrayList<>();


        try {
            String getgroup = request("http://10.182.0.99:3000/getgroup", Request.Builder::get);
            List<IdDto> group = ObjectMapperUtils.readValue(getgroup, new TypeReference<List<IdDto>>() {
            });
            group = group.stream().filter(e -> !"124".equals(e.getId()) &&
                    !"144".equals(e.getId()) &&
                    !"147".equals(e.getId()) &&
                    !"300".equals(e.getId())).collect(Collectors.toList());
            IdDto e1 = new IdDto();
            e1.setId("124");
            IdDto e2 = new IdDto();
            e2.setId("144");
            IdDto e3 = new IdDto();
            e3.setId("147");
            IdDto e4 = new IdDto();
            e3.setId("300");
            group.add(0, e1);
            group.add(1, e2);
            group.add(2, e3);
            group.add(3, e4);

            // 创建 CompletableFuture 的集合
            List<CompletableFuture<Void>> futures = group.stream()
                    .map(e -> CompletableFuture.runAsync(() -> {
                        String boss = request("http://10.182.0.99:3000/onlyTag?value=" + e.getId(), Request.Builder::get);

                        List<IdDto> result = ObjectMapperUtils.readValue(boss, new TypeReference<List<IdDto>>() {
                        });
                        idList.addAll(result);
                    }, executor))
                    .collect(Collectors.toList());

            // 等待所有 CompletableFuture 完成
            CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

            // 等待所有任务完成
            allOf.get();
            //持久化
            if (!idList.isEmpty()) {
                FileUtil.update(idList.stream().distinct().collect(Collectors.toList()));
                idList.clear();
            }


        } catch (InterruptedException | ExecutionException e) {
            System.out.println("获取id失败: ");
        } finally {
            // 关闭 ExecutorService
            executor.shutdown();
        }
    }

    @Async
    public void execution(String apiUrl, Consumer<Request.Builder> consumer) {
        request(apiUrl, consumer);
    }

    /**
     * 更好性能的方法
     *
     * @param apiUrl api url
     * @param method 方法
     */
    @Async
    public void execution(String apiUrl, HttpsMethod method) {
        Map<String, String> header = new HashMap<>();
        header.put("Origin", "http://10.182.0.99:3000");
        header.put("Referer", "http://10.182.0.99:3000/");
        try {
            method.getMethod().execution(apiUrl, header, "");
        } catch (Exception e) {
            log.error("请检查网络! 3秒后将进行重试！");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
            execution(apiUrl, method);
        }
    }

    /**
     * 要求
     *
     * @param apiUrl   api url
     * @param consumer 消费者
     * @return {@link String}
     */
    public static String request(String apiUrl, Consumer<Request.Builder> consumer) {
        try {
            // 设置请求 URL
            Request.Builder builder = new Request.Builder();
            builder.url(apiUrl);
            Map<String, String> objectObjectHashMap = new HashMap<>();
            objectObjectHashMap.put("Accept", "application/json, text/plain, */*");
            objectObjectHashMap.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
            objectObjectHashMap.put("Connection", "keep-alive");
            objectObjectHashMap.put("Content-Length", "0");
            objectObjectHashMap.put("Origin", "http://10.182.0.99:3000");
            objectObjectHashMap.put("Referer", "http://10.182.0.99:3000/");
            builder.headers(Headers.of(objectObjectHashMap));
            consumer.accept(builder);
            Request request = builder.build();
            Response response = HttpClientUtil.getUnsafeOkHttpClient().newCall(request).execute();
            // 解析响应内容
            return HttpClientUtil.getResultResponse(response);

        } catch (IOException e) {
            log.error("请检查网络! 3秒后将进行重试！");
            //e.printStackTrace();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
            return request(apiUrl, consumer);
        }
    }


}
